import * as  THREE from '../libs/three146/three.module.js' ;
import * as CANNON from '../libs/cannon-es.js';
import { CannonHelper } from '../libs/CannonHelper.js';
import { urls } from '../assets/store.js';



class Ball {
    static RADIUS  = .05715 /2;
    static MASS = .17
    static MATERIAL = new CANNON.Material('ballMaterial')

    constructor(game, x,z, id =0) {
        this.id  = id  ;
        this.startPosiiton = new THREE.Vector3(x,Ball.RADIUS,z) ;
        this.world = game.world ;
        this.game = game ;
        this.geo = new THREE.SphereGeometry(Ball.RADIUS, 16,16) ;
        this.textureLoader = new THREE.TextureLoader() ;
        
        this.createBody(x,Ball.RADIUS, z)// 高度就是半径
        this.createMesh(game.scene)
        this.name = 'ball'+ id 
        this.forward = new THREE.Vector3(0,0,-1) ;
        this.up = new  THREE.Vector3(0,1,0) ;
        this.temVec = new THREE.Vector3();
        this.temQuat = new THREE.Quaternion();
    }

    createBody(x,y,z){ 
        const body = new CANNON.Body({ 
            mass:Ball.MASS,
            position: new CANNON.Vec3(x,y,z), //不知为何用 这误差 好像是因为忘记把桌面加进物理世界，导致小球往下掉了一段距离 ，但是是怎么停住的呢
            shape: new CANNON.Sphere(Ball.RADIUS), // 这个可以复用吧
            material: Ball.MATERIAL
        })
        body.linearDamping  = body.angularDamping = .5 ;// 阻尼
        body.allowSleep = true;
        body.sleepSpeedLimit = 2 ;//速率小于1就会休眠
        body.sleepTimeLimit = .1 ;// 触发休眠后 .1s休眠
        this.body = body 
        
        this.world.addBody(body);
        return body
    }
    createMesh(scene) {
        this.mesh = new THREE.Mesh(this.geo, new THREE.MeshPhysicalMaterial({ roughness:.1, metalness:0}));
        this.mesh.name =this.name
        this.mesh.castShadow = true ;
        this.mesh.receiveShadow = true ;
        // 这里我直接用 id判断的时候出了点问题
         this.id > 0 &&  this.textureLoader.load(urls[`ball${this.id}_png`],(texture)=> { 
            this.mesh.material.map = texture
            this.mesh.material.needsUpdate =true// 这个必须加上，除非是初始化材质就设置好了                           
        })
        scene.add(this.mesh)
        return this.mesh 
    }
// 可以加一个出界的逻辑
    outOfRange(){ 

    }

    reset() {
        this.isInHole =false;
        this.body.velocity =  new  CANNON.Vec3(0,0,0) ;
        this.body.angularVelocity.set(0,0,0) ;
        this.body.position.set(...this.startPosiiton) ;
        this.mesh.position.copy(this.startPosiiton);
        this.mesh.rotation.set(0,0,0)
    }

    //hit的方向永远是裁剪空间的 z方向
    hit(strength){ 
        this.body.wakeUp() ;
        const theta = this.game.controls.getAzimuthalAngle()// 这就是球坐标的方位角 
        this.temQuat.setFromAxisAngle(this.up, theta) ;


        // const forward = this.forward.clone().applyQuaternion(this.temQuat);// 所以forward初始化的时候是 -1
        const  force = new CANNON.Vec3() ;
        force.copy(this.forward) ;
        force.scale(strength,force) ;// scale  taget
        this.body.applyImpulse(force, new CANNON.Vec3()); // 作用力 作用点
    }
    // 用y坐标判断，一般是够了
    enterHole(){ 

    }

    update(dt){ 
        this.isSleeping = this.body.sleepState === CANNON.Body.SLEEPING
        if ( this.body.position.y < 0 && this.isSleep) {
            if(!this.isInHole){ 
                this.isInHole =true ;
                // 我还是想把这个球留下来，不过这样一来这个洞进第二个球的时候呢

            }
        }else { 

            this.mesh.position.copy(this.body.position) ;// three这个方法 兼容性好
            this.mesh.quaternion.copy(this.body.quaternion)
        }
    }
}

export { Ball}